﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.Timers;
using Common;

namespace CPI311
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class GridClick : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;        // Drawing 2D stuff
        SpriteFont textFont;            // Object for a font
        Effect effect;

        Common.Plane plane;


        KeyboardState prevKeyboardState = Keyboard.GetState();
        MouseState prevMouseState = Mouse.GetState();

        Camera camera;
        ModelObject player;


        public GridClick()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            IsMouseVisible = true;
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            base.Initialize();

        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            // TODO: use this.Content to load your game content here
            camera = new Camera();
            camera.Position = new Vector3(50, 50, 50);
            camera.LookAt = Vector3.Normalize(new Vector3(-1, -2, -1));
            camera.FarPlane = 200;
            camera.AspectRatio = GraphicsDevice.Viewport.AspectRatio;

            plane = new Common.Plane(99);
            plane.Texture = Content.Load<Texture2D>("Textures/Square");
            plane.Scale *= 50;

            player = new ModelObject();
            player.Model = Content.Load<Model>("Models/Sphere");

            effect = Content.Load<Effect>("Effects/TextureEffect");
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
            // TODO: Add your update logic here
            KeyboardState keyboardState = Keyboard.GetState();
            MouseState mouseState = Mouse.GetState();

            if (mouseState.LeftButton == ButtonState.Pressed && prevMouseState.LeftButton == ButtonState.Released)
            {
                Ray ray = new Ray();
                ray.Position = GraphicsDevice.Viewport.Unproject(new Vector3(mouseState.X, mouseState.Y, 0), camera.Projection, camera.View, plane.World);
                ray.Direction = GraphicsDevice.Viewport.Unproject(new Vector3(mouseState.X, mouseState.Y, 1), camera.Projection, camera.View, plane.World) - ray.Position;

                BoundingBox boundingBox = new BoundingBox(new Vector3(-1, -0.1f, -1), new Vector3(1, 0f, 1));
                float? param;
                if ((param = boundingBox.Intersects(ray)) != null)
                {
                    float p = (float)param;
                    Vector3 position = (ray.Position + p * ray.Direction) * plane.Scale;
                    position.Y = 0;
                    position.X = (int)((position.X + 50) / 10) * 10 - 45;
                    position.Z = (int)((position.Z + 50) / 10) * 10 - 45;
                    player.Position = position;
                    Console.WriteLine(position);
                }
                
            }

            prevMouseState = mouseState;
            prevKeyboardState = keyboardState;
            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            // Clear the screen
            GraphicsDevice.Clear(Color.Black);

            effect.Parameters["LightPosition"].SetValue(camera.Position);
            effect.Parameters["DiffuseTexture"].SetValue(plane.Texture);
            effect.Parameters["TextureScale"].SetValue(new Vector2(10, 10));

            // Provide the different matrices
            effect.Parameters["View"].SetValue(camera.View);
            effect.Parameters["Projection"].SetValue(camera.Projection);
            effect.Parameters["World"].SetValue(plane.World);
            plane.Draw(effect);

            player.Draw(camera.View, camera.Projection);
            base.Draw(gameTime);
        }
    }
}
